package com.g.localmsg.starter.util;

import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Method;
import java.util.*;

public class ReflectionUtil {

    private static final Map<String, Class<?>> PRIMITIVE_TYPE_MAP = new HashMap<>();

    static {
        PRIMITIVE_TYPE_MAP.put("byte", byte.class);
        PRIMITIVE_TYPE_MAP.put("short", short.class);
        PRIMITIVE_TYPE_MAP.put("int", int.class);
        PRIMITIVE_TYPE_MAP.put("long", long.class);
        PRIMITIVE_TYPE_MAP.put("float", float.class);
        PRIMITIVE_TYPE_MAP.put("double", double.class);
        PRIMITIVE_TYPE_MAP.put("boolean", boolean.class);
        PRIMITIVE_TYPE_MAP.put("char", char.class);
        PRIMITIVE_TYPE_MAP.put("void", void.class);
    }
    private ReflectionUtil() {
    }

    public static List<Class<?>> getParameterTypes(String[] parameterTypes) {
        List<Class<?>> parameterTypeList = new ArrayList<>(parameterTypes.length);
        for (String parameterType : parameterTypes) {
            Class<?> parameterClass = PRIMITIVE_TYPE_MAP.get(parameterType);
            if (parameterClass == null) {
                try {
                    parameterClass = ClassUtils.forName(parameterType, Thread.currentThread().getContextClassLoader());
                    parameterTypeList.add(parameterClass);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException("Class not found: " + parameterType);
                }
            }
        }
        return parameterTypeList;
    }

        public static Method getMethod(Class<?> clazz, String methodName, List<Class<?>> parameterTypes){
            try {
                return clazz.getMethod(methodName, parameterTypes.toArray(new Class<?>[0]));
            } catch (NoSuchMethodException e) {
                // 如果找不到方法，则遍历所有方法，进行参数兼容性匹配
                for (Method method : clazz.getMethods()) {
                    if (method.getName().equals(methodName)
                            && isParameterTypesCompatible(method.getParameterTypes(), parameterTypes)) {
                        return method;
                    }
                }
                throw new IllegalArgumentException(String.format("在类 %s 中找不到匹配的方法: %s，参数类型: %s", clazz.getName(),
                        methodName, parameterTypes));
            }
    }

    private static boolean isParameterTypesCompatible(Class<?>[] methodParameterTypes, List<Class<?>> givenParameterTypes) {
        if (methodParameterTypes.length != givenParameterTypes.size()) {
            return false;
        }
        for (int i = 0; i < methodParameterTypes.length; i++) {
            if (!isAssignableFrom(methodParameterTypes[i], givenParameterTypes.get(i))) {
                return false;
            }
        }
        return true;
    }

    private static boolean isAssignableFrom(Class<?> targetType, Class<?> sourceType) {
        // 处理基本类型与包装类型的兼容性
        if (targetType.isPrimitive()) {
            targetType = ClassUtils.resolvePrimitiveIfNecessary(targetType);
        }
        if (sourceType.isPrimitive()) {
            sourceType = ClassUtils.resolvePrimitiveIfNecessary(sourceType);
        }
        return targetType.isAssignableFrom(sourceType);
    }


    public static Object getSourceObject(Object bean) {
        if (!(bean instanceof Advised)) {
            return bean;
        }
        TargetSource targetSource = ((Advised) bean).getTargetSource();
        try {
            return targetSource.getTarget();
        } catch (Exception e) {
            throw new RuntimeException("获取原始对象失败", e);
        }
    }
}
